#include <iostream>
#include <map>
#include <sstream>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/find_iterator.hpp>
#include "RiskMeasureReader.h"
#include "../utils/Csv.h"


using namespace std;
using namespace boost;

namespace quic
{
    RiskMeasureReader::RiskMeasureReader(void)
    {
    }

    RiskMeasureReader::~RiskMeasureReader(void)
    {
    }

    shared_ptr<RiskMeasure> RiskMeasureReader::read(string file)
    {
        Nodes nodes;
        Edges edges;
        Csv csv(file);

        shared_ptr<RiskMeasure> result(new RiskMeasure("Price", false, "Price"));
        nodes[result->getName()] = result;

        while(csv.hasNextRecord())
        {
            vector<string> record = csv.nextRecord();

            // Risk measure must have at least 4 records, also ignore comments
            if(record.size() < 4 || record[0].find("//") == 0) continue;

            shared_ptr<RiskMeasure> rm(new RiskMeasure(record[0],
                to_lower_copy(record[1]) == "true" || to_lower_copy(record[1]) == "all", record[3]));
            split(rm->parameters, record[2], is_any_of(","));
            for(unsigned int i=4;i<record.size();i++)
                edges.insert(Edge(rm->getName(),record[i]));

            nodes[rm->getName()] = rm;
        };

        linkNodes(nodes,edges);

        return result;
    }

    void RiskMeasureReader::linkNodes(Nodes &nodes, Edges &edges)
    {
        if(nodes.size()<2)
            throw "Expecting nodes in the risk measure tree other than 'Price'";

        for(Edges::iterator it = edges.begin(); it != edges.end(); ++it)
        {
            // Parent is RiskMeasure.Output, just take the RiskMeasure part
            string parent = it->second;
            int index = parent.find('.');
            if(index != string::npos)
                parent = parent.substr(0,index);

            // Check for issues (i.e. edges connecting to non existing node)
            if(nodes.find(it->first) == nodes.end() || nodes.find(parent) == nodes.end()) {
                ostringstream stm ;
                stm << format("Edge connecting '%s' to '%s' refers to non existing node") %
                        it->first % parent;
                throw stm.str();
            }

            // connect the nodes defined by the edge
            nodes[parent]->addChild(nodes[it->first]);
        }
    }
};
